/*Copyright (C) 2009 Careil Baptiste

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "Error.h"
#include "Network.h"
#include "TCP.h"
#include "dll.h"

#include <string.h>


CSLP_TCPSOCKET DLL_IMPEXP CSLP_InitTCPSocket()
{
#ifdef WIN32
  InitWSA();
#endif /* WIN32 */
  return socket(AF_INET, SOCK_STREAM, 0);
}

CSLP_NETWORK_ERROR DLL_IMPEXP CSLP_Connect(CSLP_TCPSOCKET sock, unsigned long IP, unsigned short port)
{
  SOCKADDR_IN sockIn;
  sockIn.sin_addr.s_addr = IP;
  sockIn.sin_family = AF_INET;
  sockIn.sin_port = htons(port);
  memset(sockIn.sin_zero, 0, 8);
  if (connect(sock, (SOCKADDR*)&sockIn, sizeof(sockIn)) != 0)
    {
      return CSLP_GetLastNetworkError();
    }
  return NONE;
}

CSLP_NETWORK_ERROR DLL_IMPEXP CSLP_SendString(CSLP_TCPSOCKET sock, const char* str)
{
  return CSLP_Send(sock, str, strlen(str) * sizeof(*str) + 1);
}

CSLP_NETWORK_ERROR DLL_IMPEXP CSLP_Send(CSLP_TCPSOCKET sock, const char* data, int len)
{
  int len_send, len_to_send;

  len_to_send = len;
  CSLP_NETWORK_ERROR retVal = NONE;
  do
    {
      len_send = send(sock, &data[len - len_to_send], len_to_send, MSG_NOSIGNAL);
      if (len_send == -1)
        {
          return CSLP_GetLastNetworkError();
        }
      len_to_send -= len_send;
    } while (len_to_send);
  return retVal;
}

CSLP_NETWORK_ERROR DLL_IMPEXP CSLP_Receive(CSLP_TCPSOCKET sock, void* data, size_t dataLen, size_t* bytesWrite)
{
  CSLP_NETWORK_ERROR retVal = NONE;
  int lenRcv = recv(sock, data, dataLen, 0);
  if (lenRcv == -1)
    {
      retVal = CSLP_GetLastNetworkError();
    }
  else
    {
      *bytesWrite = lenRcv;
    }
  return retVal;
}

int DLL_IMPEXP CSLP_Listen(CSLP_TCPSOCKET sock, unsigned short port)
{
  int retVal = 0;
  SOCKADDR_IN sockIn;
  sockIn.sin_addr.s_addr = htonl(INADDR_ANY);
  sockIn.sin_family = AF_INET;
  sockIn.sin_port = htons(port);
  memset(sockIn.sin_zero, 0, 8);

  if (bind(sock, (SOCKADDR*)&sockIn, sizeof(sockIn)) != 0)
    {
      retVal = -1;
    }
  else
    {
      if (listen(sock, 8) != 0)
	{
	  retVal = -1;
	}
    }
  return retVal;
}

int DLL_IMPEXP CSLP_Accept(CSLP_TCPSOCKET serverSocket, CSLP_TCPSOCKET* clientSocket, unsigned long* clientIP, unsigned short* clientPort)
{
  int retVal = 0;
  SOCKADDR_IN sockIn;
  socklen_t sockInLen;

  *clientSocket = accept(serverSocket, (SOCKADDR*)&sockIn, &sockInLen);
  if (*clientSocket != CSLP_INVALID_SOCKET)
    {
#ifdef WIN32
      InitWSA();
#endif /* WIN32 */
      if (clientIP != NULL)
	{
	  *clientIP = sockIn.sin_addr.s_addr;
	}
      if (clientPort != NULL)
	{
	  *clientPort = htons(sockIn.sin_port);
	}
    }
  else
    {
      retVal = -1;
    }
  return retVal;
}

void DLL_IMPEXP CSLP_CloseTCPSocket(CSLP_TCPSOCKET sock)
{
#ifdef WIN32
  if (closesocket((SOCKET)(sock)) == 0)
    {
      CloseWSA();
    }
#else /* WIN32 */
  close((int)(sock));
#endif /* !WIN32 */
}

